import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:meta/meta.dart';
import 'package:ost_flutter_module/class/entity/base_entity/base_entity.dart';

import 'api_exception.dart';
import 'header_interceptor.dart';
import 'response_result.dart';
import 'token_interceptor.dart';
import 'url_constants.dart';

enum Method { GET, POST, DELETE, PUT }

class HttpManager {
  Dio _dio;

  static final HttpManager _instance = HttpManager._internal();

  HttpManager._internal() {
    _dio = Dio();
    _dio.options.baseUrl = BASE_URL;
    _dio.options.connectTimeout = 30000;
    _dio.options.receiveTimeout = 30000;
    _dio.options.contentType = Headers.jsonContentType;
    _dio.interceptors.clear();
    _dio.interceptors
      ..add(HeaderInterceptor())
      ..add(TokenInterceptor(_dio))
      ..add(LogInterceptor(requestBody: true, responseBody: true));
  }

  factory HttpManager.getInstance() => _instance;

  Future<ResponseResult<T>> syncRequest<T>(
    url, {
    @required dynamic params,
    Method method = Method.POST,
    String baseUrl = BASE_URL,
    String contentType = Headers.jsonContentType,
    Map<String, dynamic> headers,
  }) async {
    try {
      Response response = await _dio.request(
        url,
        data: params,
        queryParameters: method == Method.GET ? params : null,
        options: RequestOptions(
          method: method.toString().split('.').last.toLowerCase(),
          contentType: contentType,
          baseUrl: baseUrl,
          headers: headers ?? {},
        ),
      );
      if (response != null) {
        var entity = BaseEntity<T>.fromJson(response.data);
        if (entity.code == 0) {
          return ResponseResult.success(entity.data);
        } else {
          return ResponseResult.failure1(ApiException(
              code: entity.code, showMsg: entity.message, msg: entity.message));
        }
      } else {
        return ResponseResult.failure1(ApiException(
            code: ERROR_CODE_UNKNOWN, showMsg: "未知错误", msg: "未知错误"));
      }
    } on Exception catch (e) {
      return ResponseResult.failure(e);
    } on Error catch (e) {
      return ResponseResult.failure2(e);
    } catch (_) {
      return ResponseResult.failure1(
          ApiException(code: ERROR_CODE_UNKNOWN, showMsg: "未知错误", msg: "未知错误"));
    }
  }

  Future<ResponseResult<List<T>>> syncRequestList<T>(
    url, {
    @required dynamic params,
    Method method = Method.POST,
    String baseUrl = BASE_URL,
    String contentType = Headers.jsonContentType,
    Map<String, dynamic> headers,
  }) async {
    try {
      Response response = await _dio.request(
        url,
        data: params,
        queryParameters: method == Method.GET ? params : null,
        options: RequestOptions(
          method: method.toString().split('.').last.toLowerCase(),
          contentType: contentType,
          baseUrl: baseUrl,
          headers: headers ?? {},
        ),
      );
      if (response != null) {
        var entity = BaseEntityList<T>.fromJson(response.data);
        if (entity.code == 0) {
          return ResponseResult.success(entity.data);
        } else {
          return ResponseResult.failure1(ApiException(
              code: entity.code, showMsg: entity.message, msg: entity.message));
        }
      } else {
        return ResponseResult.failure1(ApiException(
            code: ERROR_CODE_UNKNOWN, showMsg: "未知错误", msg: "未知错误"));
      }
    } on Exception catch (e) {
      return ResponseResult.failure(e);
    } on Error catch (e) {
      return ResponseResult.failure2(e);
    } catch (_) {
      return ResponseResult.failure1(
          ApiException(code: ERROR_CODE_UNKNOWN, showMsg: "未知错误", msg: "未知错误"));
    }
  }
}

Map<String, dynamic> buildParams(
    {int pageIndex = 1,
    int pageSize = 10,
    String condition = "",
    String group = "",
    String orders = ""}) {
  var fuse = utf8.fuse(base64);
  if (condition != null && condition.isNotEmpty) {
    condition = fuse.encode(condition);
  }
  if (orders != null && orders.isNotEmpty) {
    orders = fuse.encode(orders);
  }
  return {
    "pageNum": pageIndex,
    "pageSize": pageSize,
    "condition": condition,
    "groups": group,
    "orders": orders
  };
}
